#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>

#define BUFFER_SIZE 5
#define PRODUCER_NUM 3
#define CONSUMER_NUM 4
#define STUDENT_ID "2023090902018"

char buffer[BUFFER_SIZE] = {0};
int in = 0, out = 0;

sem_t empty, full;
sem_t mutex;
pthread_mutex_t file_mutex;
FILE *fp;
int producer_finished = 0;

void *producer(void *arg) 
{
    int num = *((int*)arg);
    char c;
    while (1) 
    {
        pthread_mutex_lock(&file_mutex);
        c = fgetc(fp);
        if (c == EOF) 
        {
            pthread_mutex_unlock(&file_mutex);
            producer_finished = 1;
            for(int i = 0; i < CONSUMER_NUM; i++)
            {
                sem_post(&full);
            }
            printf("[%s][生产者]线程[%d]退出...\n", STUDENT_ID, num);
            break;
        }
        printf("[%s][生产者]线程[%d]已经取得一个数据[%c]\n", STUDENT_ID, num, c);
        pthread_mutex_unlock(&file_mutex);

        sem_wait(&empty);
        sem_wait(&mutex);
        printf("[%s][生产者]线程[%d]获得缓冲区的[mutex]\n", STUDENT_ID, num);

        buffer[in] = c;
        in = (in + 1) % BUFFER_SIZE;
        printf("[%s][生产者]线程[%d]已将一个数据[%c]送入缓冲区\n", STUDENT_ID, num, c);

        sem_post(&mutex);
        sem_post(&full);
        sleep(1);
    }

    return NULL;
}

void *consumer(void *arg) 
{
    int num = *((int*)arg);
    char c;
    int finished = 0;
    while (1) 
    {
        sem_wait(&full);
        sem_wait(&mutex);
        printf("[%s][消费者]线程[%d]获得缓冲区的[mutex]\n", STUDENT_ID, num);

        if(producer_finished && buffer[out] == '\0')
        {
            sem_post(&mutex);
            sem_post(&empty);
            printf("[%s][消费者]线程[%d]退出...\n", STUDENT_ID, num);
            break;
        }
        else
        {
            c = buffer[out];
            buffer[out] = '\0';
            out = (out + 1) % BUFFER_SIZE;
            printf("[%s][消费者]线程[%d]读取到数据[%c]\n", STUDENT_ID, num, c);
            sem_post(&mutex);
            sem_post(&empty);
        }
        sleep(1);
    }
    return NULL;
}

int main() 
{
    fp = fopen("input.txt", "r");
    if (!fp) 
    {
        perror("fopen input.txt");
        return 1;
    }

    sem_init(&empty, 0, BUFFER_SIZE);
    sem_init(&full, 0, 0);
    sem_init(&mutex, 0, 1);
    pthread_mutex_init(&file_mutex, NULL);

    pthread_t producers[3], consumers[4];
    int producer_nums[PRODUCER_NUM];
    int consumer_nums[CONSUMER_NUM];

    // 创建生产者线程
    for (int i = 0; i < PRODUCER_NUM; i++) 
    {
        producer_nums[i] = i;
        pthread_create(&producers[i], NULL, producer, &producer_nums[i]);
    }

    // 创建消费者线程
    for (int i = 0; i < CONSUMER_NUM; i++) 
    {
        consumer_nums[i] = i;
        pthread_create(&consumers[i], NULL, consumer, &consumer_nums[i]);
    }

    // 生产者
    for (int i = 0; i < PRODUCER_NUM; i++) 
    {
        pthread_join(producers[i], NULL);
    }

    // 消费者
    for (int i = 0; i < 4; i++) 
    {
        pthread_join(consumers[i], NULL);
    }

    // 清理资源
    sem_destroy(&empty);
    sem_destroy(&full);
    sem_destroy(&mutex);
    pthread_mutex_destroy(&file_mutex);
    fclose(fp);

    return 0;
}